#include "beats.h"

#define MAXRRINTERVALS 5000 // 最大有效的rr间期

Beats::Beats(QObject* parent)
    : QObject { parent }
{
}
//判断点是否在多边形内部
bool Beats::isInPolygon(QPoint& point, QList<QPoint>& points)
{
    if (points.size() < 3) {
        return false;
    }
    int n = points.size();
    int nCross = 0;
    for (int i = 0; i < n; i++) {
        const QPointF& p1 = points[i];
        const QPointF& p2 = points[(i + 1) % n];
        // 求解 y=point.y 与 p1 p2 的交点
        // p1p2 与 y=point.y平行
        if (p1.y() == p2.y())
            continue;
        // 交点在p1p2延长线上
        if (point.y() < qMin(p1.y(), p2.y()))
            continue;
        // 交点在p1p2延长线上
        if (point.y() >= qMax(p1.y(), p2.y()))
            continue;
        // 求交点的 X 坐标
        double x = ((point.y() - p1.y()) * (p2.x() - p1.x())) / (p2.y() - p1.y()) + p1.x();
        // 只统计单边交点
        if (x > point.x())
            nCross++;
    }
    return nCross % 2 == 1;
}

int Beats::getSelectedBeatsCount() const
{
    return selectedBeatsCount;
}

void Beats::setSelectedBeatsCount(int newSelectedBeatsCount)
{
    if (selectedBeatsCount == newSelectedBeatsCount)
        return;
    selectedBeatsCount = newSelectedBeatsCount;
    emit selectedBeatsCountChanged();
}

Beats& Beats::getInstance()
{
    static Beats instance; // 静态局部变量，确保只初始化一次
    return instance;
}
void Beats::saveQHashToBinaryFile(QHash<int, QHash<unsigned char, int16_t>>& hash)
{
    // QHash<int, QHash<unsigned char, int16_t>> hash;
    // hash.insert(1, { { 1, 6 } });
    // hash.insert(2, { { 2, 7 } });
    // hash.insert(3, { { 3, 8 } });
    // hash.insert(4, { { 4, 9 } });
    // hash.insert(5, { { 5, 10 } });

    QString fileName = "../data/beats.bin";
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly)) {
        qDebug() << "Cannot open file for writing:" << file.errorString();
        return;
    }

    QDataStream out(&file);
    out.setVersion(QDataStream::Qt_6_6); // 设置数据流版本

    out << hash;

    file.close();
    qDebug() << "心跳数据写入完成";
}

void Beats::loadQHashFromBinaryFile()
{
    QString fileName = "../data/beats.bin";
    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly)) {
        qDebug() << "Cannot open file for reading:" << file.errorString();
        return;
    }

    QDataStream in(&file);
    in.setVersion(QDataStream::Qt_6_6); // 设置数据流版本
    in >> data;
    file.close();
    qDebug() << "QHash loaded from binary file:" << fileName;
    processBeatsData();
    // qDebug() << rPeaksInAlls;
}
/**
 * @brief 计算rr间期等数据处理
 */
void Beats::processBeatsData()
{
    rPeaksInAlls = data.keys();
    std::sort(rPeaksInAlls.begin(), rPeaksInAlls.end()); //排序
    //计算rr间期
    for (int i = 0; i < rPeaksInAlls.size(); i++) {
        int rrIntervals = 0;
        if (i > 0) {
            rrIntervals = std::round(static_cast<float>(rPeaksInAlls[i] - rPeaksInAlls[i - 1]) / ecg.sampleRate() * 1000);
        }
        if (rrIntervals > MAXRRINTERVALS) {
            rrIntervals = 0;
        }
        data[rPeaksInAlls[i]].insert(1, rrIntervals);
        data[rPeaksInAlls[i]].remove(selectedIndex);
    }
}

QVector<int> Beats::getFragmentBeats(int start, int duration)
{
    if (start < 0) {
        start = 0;
    }
    //start大小需要验证
    // if (start > signalSize - 1) {
    //     start = signalSize - 1;
    // }
    int end = start + duration / 1000 * ecg.sampleRate();
    if (end == 0) {
        end = rPeaksInAlls[rPeaksInAlls.size() - 1];
    }
    QVector<int> result;
    std::copy_if(rPeaksInAlls.begin(), rPeaksInAlls.end(), std::back_inserter(result),
        [start, end](int value) {
            return value >= start && value <= end;
        });
    return result;
}
//快捷键设置已选中心搏的label
QVector<int> Beats::shortcutSetLabel(QString keyStr)
{
    if (selectedBeats.size() > 0) {
        for (int index = 0; index < labels.size(); ++index) {
            if (labels[index].value("label") == keyStr) {
                //将data中原有选中label改为对应标签
                QHash<int, bool>::const_iterator i;
                for (i = selectedBeats.constBegin(); i != selectedBeats.constEnd(); ++i) {
                    if (data.contains(i.key())) {
                        data[i.key()][labelIndex] = index;
                    }
                }
                saveQHashToBinaryFile(data);
                return selectedBeats.keys();
            }
        }
    }
    return {};
}

QList<int> Beats::getRrIntervalChartData(int start, int duration, int width, int height)
{
    int currentDuration = duration;
    if (currentDuration == 0) {
        currentDuration = ecg.duration();
    }
    int sampleRate = ecg.sampleRate();
    QVector<int> beats = getFragmentBeats(start, duration);
    // qDebug() <<ecg.duration();
    QList<int> pixelData(width * height * 4, 0); //构建一个像素数据，每个像素点报告rgba4个字节
    int preRPeaksInAll = -1, rrIntervals, rPeaksInAll, x, y;
    for (int i = 0; i < beats.size(); ++i) {
        rPeaksInAll = beats[i];
        if (preRPeaksInAll == -1) {
            preRPeaksInAll = rPeaksInAll;
            continue;
        }
        rrIntervals = data[rPeaksInAll][rrIntervalsIndex];
        if (rrIntervals == 0) {
            preRPeaksInAll = rPeaksInAll;
            continue;
        }
        //有标签并且标签不为X的才计算
        if (data[rPeaksInAll][labelIndex] != INVALID && data[rPeaksInAll][labelIndex] != X) {
            x = (rPeaksInAll - start) / sampleRate * 1000.0f / currentDuration * width;
            y = (2000 - rrIntervals) / 2000.0f * height;
            // if(x < 0) x = 0;
            // if(x > width) x = width - 1;
            if (y < 0)
                y = 0;
            if (y > height)
                y = height - 1;
            pixelData[(y * width + x) * 4 + 0] = 119;
            pixelData[(y * width + x) * 4 + 1] = 125;
            pixelData[(y * width + x) * 4 + 2] = 235;
            pixelData[(y * width + x) * 4 + 3] = 255;
        }
        preRPeaksInAll = rPeaksInAll;
    }
    // qDebug() << pixelData;
    return pixelData;
}

QList<int> Beats::getRrScatterChartData(int start, int duration, int width, int height, int axisMaxValue, QString label1, QString label2)
{
    QVector<int> beats = getFragmentBeats(start, duration);
    QList<int> pixelData(width * height * 4, 0); //构建一个像素数据，每个像素点报告rgba4个字节
    listBeats.clear();
    int preRPeaksInAll = -1, rrIntervals = 0, rPeaksInAll = -1, preRrIntervals = 0, currentLabelIndex = -1, preLabelIndex = -1, firstLabelIndex = -1, x, y;
    // beats = [], rPeaksInAllArr = []
    int label1Index = -1, label2Index = -1;
    for (int i = 0; i < labels.size(); ++i) {
        QHash label = labels[i];
        if (label["label"] == label1) {
            label1Index = i;
        }
        if (label["label"] == label2) {
            label2Index = i;
        }
    }

    for (int i = 0; i < beats.size(); ++i) {
        rPeaksInAll = beats[i];
        currentLabelIndex = data[rPeaksInAll][labelIndex];
        if (label2 == 'X') {
            //统计带X的
            if (currentLabelIndex == INVALID) {
                preRPeaksInAll = -1;
                preRrIntervals = 0;
                firstLabelIndex = -1;
                preLabelIndex = -1;
                continue;
            }
        } else {
            if ((currentLabelIndex == INVALID || currentLabelIndex == X) && label2 != 'S' && label2 != 'V') {
                //除了RS和RV，有标签并且标签不为X的才画图
                preRPeaksInAll = -1;
                preRrIntervals = 0;
                firstLabelIndex = -1;
                preLabelIndex = -1;
                continue;
            }
        }
        if (preRPeaksInAll < 0) {
            preRPeaksInAll = rPeaksInAll;
            preRrIntervals = 0;
            firstLabelIndex = -1;
            preLabelIndex = currentLabelIndex;
            continue;
        }
        rrIntervals = data[rPeaksInAll][rrIntervalsIndex];
        if (label1 == 'S' && label2 == 'V') {
            //房早室早叠加
            if (label1Index != preLabelIndex && label2Index != preLabelIndex && J != preLabelIndex) {
                firstLabelIndex = preLabelIndex;
                preRPeaksInAll = rPeaksInAll;
                preRrIntervals = rrIntervals;
                preLabelIndex = currentLabelIndex;
                continue;
            }
        } else {
            if ((label1Index != -1 && firstLabelIndex != -1 && label1Index != firstLabelIndex) || (label2Index != -1 && preLabelIndex != -1 && label2Index != preLabelIndex)) {
                firstLabelIndex = preLabelIndex;
                preRPeaksInAll = rPeaksInAll;
                preRrIntervals = rrIntervals;
                preLabelIndex = currentLabelIndex;
                continue;
            }
        }
        //前后都在有效范围内
        if (rrIntervals > 0 && preRrIntervals > 0 && rrIntervals > 0 && preRrIntervals > 0) {
            float rr = rrIntervals;
            if (rr >= axisMaxValue) {
                rr = axisMaxValue - 1;
            }
            float prr = preRrIntervals;
            if (prr >= axisMaxValue) {
                prr = axisMaxValue - 1;
            }
            x = prr * width / axisMaxValue;
            y = height - rr * height / axisMaxValue;
            if (x >= width)
                x = width;
            if (y >= height)
                y = height;
            pixelData[(y * width + x) * 4 + 3] = 255;
            //弄成一个十字形
            if (x - 1 >= 0)
                pixelData[(y * width + x - 1) * 4 + 3] = 255;
            if (x + 1 <= width - 1)
                pixelData[(y * width + x + 1) * 4 + 3] = 255;
            if (y - 1 >= 0)
                pixelData[((y - 1) * width + x) * 4 + 3] = 255;
            if (y + 1 <= height - 1)
                pixelData[((y + 1) * width + x) * 4 + 3] = 255;
            if (preLabelIndex == V) {
                //红色
                pixelData[(y * width + x) * 4 + 0] = 200;
                //弄成一个十字形
                if (x - 1 >= 0)
                    pixelData[(y * width + x - 1) * 4 + 0] = 200;
                if (x + 1 <= width - 1)
                    pixelData[(y * width + x + 1) * 4 + 0] = 200;
                if (y - 1 >= 0)
                    pixelData[((y - 1) * width + x) * 4 + 0] = 200;
                if (y + 1 <= height - 1)
                    pixelData[((y + 1) * width + x) * 4 + 0] = 200;
            } else if (preLabelIndex == S) {
                //蓝色
                pixelData[(y * width + x) * 4 + 2] = 200;
                //弄成一个十字形
                if (x - 1 >= 0)
                    pixelData[(y * width + x - 1) * 4 + 2] = 200;
                if (x + 1 <= width - 1)
                    pixelData[(y * width + x + 1) * 4 + 2] = 200;
                if (y - 1 >= 0)
                    pixelData[((y - 1) * width + x) * 4 + 2] = 200;
                if (y + 1 <= height - 1)
                    pixelData[((y + 1) * width + x) * 4 + 2] = 200;
            } else if (preLabelIndex == J) {
                //绿色
                pixelData[(y * width + x) * 4 + 1] = 200;
                //弄成一个十字形
                if (x - 1 >= 0)
                    pixelData[(y * width + x - 1) * 4 + 1] = 200;
                if (x + 1 <= width - 1)
                    pixelData[(y * width + x + 1) * 4 + 1] = 200;
                if (y - 1 >= 0)
                    pixelData[((y - 1) * width + x) * 4 + 1] = 200;
                if (y + 1 <= height - 1)
                    pixelData[((y + 1) * width + x) * 4 + 1] = 200;
            }
            listBeats.append(preRPeaksInAll);
            data[preRPeaksInAll][pixelXIndex] = prr;
            data[preRPeaksInAll][pixelYIndex] = rr;
            // beats.push({ rPeaksInAll: preRPeaksInAll, x: prr, y: rr })
            // rPeaksInAllArr.push(preRPeaksInAll)
        }
        preRPeaksInAll = rPeaksInAll;
        preRrIntervals = rrIntervals;
        firstLabelIndex = preLabelIndex;
        preLabelIndex = currentLabelIndex;
    }
    return pixelData;
}
//圈选rr散点图的心搏
int Beats::circleSelectRrScatterChartData(const QVariantList& array)
{
    QPolygonF polygon;
    for (const QVariant& row : array) {
        int i = 0;
        QPoint point;
        for (const QVariant& item : row.toList()) {
            if (i == 0) {
                point.setX(item.toInt());
                i++;
            } else {
                point.setY(item.toInt());
            }
        }
        polygon.append(point);
    }
    // qDebug() << points;
    circleSelectBeats.clear();
    // QDateTime startTime = QDateTime::currentDateTime();
    for (int i = 0; i < listBeats.size(); ++i) {
        int rPeaksInAll = listBeats[i];
        if (data[rPeaksInAll].contains(pixelXIndex) && data[rPeaksInAll].contains(pixelYIndex)) {
            QPoint point(data[rPeaksInAll][pixelXIndex], data[rPeaksInAll][pixelYIndex]);
            //判断点是否在多边形内
            if (polygon.containsPoint(point, Qt::OddEvenFill)) {
                circleSelectBeats.append(rPeaksInAll);
            }
        }
    }
    // QDateTime endTime = QDateTime::currentDateTime();
    // qint64 diffInMilliseconds = startTime.msecsTo(endTime);
    // qDebug() << "时间差（毫秒）: " << diffInMilliseconds;
    return circleSelectBeats.size();
}
//设置选中的心搏
QVector<int> Beats::setSelectedBeats(QVector<int> rPeaksInAlls)
{
    int count = 0;
    //将data中原有选中心搏状态改为未选中
    QHash<int, bool>::const_iterator i;
    for (i = selectedBeats.constBegin(); i != selectedBeats.constEnd(); ++i) {
        if (data.contains(i.key()))
            data[i.key()].remove(selectedIndex);
    }
    QVector<int> oldSelected = selectedBeats.keys();
    //删除原有选中的SelectedBeats
    selectedBeats.clear();

    //设置新的SelectedBeats并修改data
    for (int i = 0; i < rPeaksInAlls.size(); ++i) {
        if (data.contains(rPeaksInAlls[i])) {
            data[rPeaksInAlls[i]].insert(selectedIndex, 1);
            selectedBeats.insert(rPeaksInAlls[i], 1);
            count++;
        }
    }
    setSelectedBeatsCount(selectedBeats.size());
    return oldSelected;
}
